﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace FeedAntGame.Sprite
{
    
    abstract class BaseSprite
    {
        /************************************************************************/
        /*                       Attributes                                               */
        /************************************************************************/
        
        protected Texture2D textureImage;
        protected Point frameSize;
        Point currentFrame;
        protected Point sheetSize;
        int collisionOffset;
        int timeSinceLastFrame = 0;
        int millisecondsPerFrame;
        const int defaultMillisecondsPerFrame = 16;
        protected float scale = 1;
        protected Vector2 speed;
        protected Vector2 position;
        protected float rotation = 0;
        protected Vector2 origin;
        protected float scaleWidth = 1;
        protected float scaleHeight = 1;

        protected bool visible = true;
        protected ANIMATE_TYPE animateType = ANIMATE_TYPE.NORMAL;
        private int animateSign = 1; // use for animate circle
        protected SpriteEffects spriteEffect = SpriteEffects.None;
        protected bool frameSwitch = true;
        private Texture2D collisionRectImage = null;
        protected Color color;
        protected bool isLive = true;
        private bool drawEachScale = false;
        public enum ANIMATE_TYPE { NORMAL, INVERT, CIRCLE }
        /************************************************************************/
        /*                      Get/Set                                                */
        /************************************************************************/

        /// <summary>
        /// Available only drawEachScale = true or call setEdgeScale function
        /// </summary>
        public float ScaleWidth
        {
            get { return scaleWidth; }
            set { scaleWidth = value; }
        }
        /// <summary>
        /// Available only drawEachScale = true or call setEdgeScale function
        /// </summary>
        public float ScaleHeight
        {
            get { return scaleHeight; }
            set { scaleHeight = value; }
        }
        /// <summary>
        /// Get isLive, Set isLive => visible , framSwitch
        /// </summary>
        public bool IsLive
        {
            get { return isLive; }
            
            set 
            { 
                isLive = value;
                visible = isLive;
                frameSwitch = isLive;
            }
        }
        public Color MyColor
        {
            get { return color; }
            set { color = value; }
        }

        public Texture2D CollisionRectImage
        {
            get { return collisionRectImage; }
            set { collisionRectImage = value; }
        }

        public bool FrameSwitch
        {
            get { return frameSwitch; }
            set { frameSwitch = value; }
        }

        public SpriteEffects SpriteEffect
        {
            get { return spriteEffect; }
            set { spriteEffect = value; }
        }

        /// <summary>
        /// Type of frame animate Direction
        /// </summary>
        public ANIMATE_TYPE AnimateType
        {
            get { return animateType; }
            set { animateType = value; }
        }

        public virtual bool Visible
        {
            get { return visible; }
            set { visible = value; }
        }

        public virtual float Scale
        {
            get { return scale; }
            set
            { 
                scale = value;
                scaleWidth = value;
                scaleHeight = value;
            }
        }

        public virtual Texture2D TextureImage
        {
            get { return textureImage; }
        }
        public virtual Vector2 Origin
        {
            get { return origin; }
            set { origin = value; }
        }

        public float Height
        {
            get 
            {
                if (drawEachScale)
                {
                    return textureImage.Height * scaleHeight;
                }
                return textureImage.Height * scale;
            }
        }

        public float RealHeight
        {
            get { return textureImage.Height; }
        }
        public float RealWidth
        {
            get { return textureImage.Width; }
        }
        public float Width
        {
            get 
            {
                if (drawEachScale)
                {
                    return textureImage.Width * scaleWidth;
                }
                return textureImage.Width * scale;
            }
        }
        /// <summary>
        /// Get/Set topLeftPos
        /// </summary>
        public Vector2 Position
        {
            get { return position; }
            set { position = value; }
        }

        /// <summary>
        /// Get Direction
        /// </summary>
        public abstract Vector2 Direction { get; }
        public float ScroreValue { get;  set; }
        public Rectangle collisionRect
        {
            get
            {
                return new Rectangle(
                    (int)position.X + collisionOffset,
                    (int)position.Y + collisionOffset,
                    (int)(frameSize.X * scale  - (collisionOffset * 2)),
                    (int)(frameSize.Y * scale  - (collisionOffset * 2)));
            }
        }

        public float Rotation
        {
            get { return rotation; }
            set { rotation = value; }
        }
        public string collisionCueName { get; private set;}
        /************************************************************************/
        /*                      Constructors                                                */
        /************************************************************************/
        /// <summary>
        /// Must not use. Only for inheritance class's legal.
        /// </summary>
        
        public BaseSprite(Texture2D textureImage, Vector2 position, Point frameSize,
                int collisionOffset, Point currentFrame, Point sheetSize, Vector2 speed, string collisionCueName, int scoreValue,
                float scale)
            : this(textureImage, position, frameSize, collisionOffset, currentFrame, sheetSize, speed
            , defaultMillisecondsPerFrame, collisionCueName, scoreValue,scale)
        {

        }
        public BaseSprite(Texture2D textureImage, Vector2 position, Point frameSize,
                int collisionOffset, Point currentFrame, Point sheetSize, Vector2 speed,
                int millisecondsPerFrame, string collisionCueName, int scoreValue, float scale)
        {
            this.textureImage = textureImage;
            this.position = position;
            this.frameSize = frameSize;
            this.collisionOffset = collisionOffset;
            this.currentFrame = currentFrame;
            this.sheetSize = sheetSize;
            this.speed = speed;
            this.millisecondsPerFrame = millisecondsPerFrame;
            this.collisionCueName = collisionCueName;
            this.ScroreValue = scoreValue;
            this.scale = scale;
            this.origin = Vector2.Zero;
            this.color = Color.FromNonPremultiplied(255, 255, 255, 255);
            
        }

        
        /************************************************************************/
        /*                         Function                                             */
        /************************************************************************/
        public virtual void Update(GameTime gameTime, Rectangle clientBounds)
        {               
            timeSinceLastFrame += gameTime.ElapsedGameTime.Milliseconds;
            if (timeSinceLastFrame > millisecondsPerFrame && frameSwitch)
            {
                timeSinceLastFrame = 0;
                switch (animateType)
                {
                    case ANIMATE_TYPE.NORMAL:
                        ++currentFrame.X;
                        if (currentFrame.X >= sheetSize.X)
                        {
                            currentFrame.X = 0;
                            ++currentFrame.Y;
                            if (currentFrame.Y >= sheetSize.Y)
                                currentFrame.Y = 0;
                        }
                        break;
                    case ANIMATE_TYPE.INVERT:
                        --currentFrame.X;
                        if (currentFrame.X < 0)
                        {
                            currentFrame.X = sheetSize.X - 1;
                            --currentFrame.Y;
                            if (currentFrame.Y <0 )
                                currentFrame.Y = sheetSize.Y -1;
                        }
                        break;
                    case ANIMATE_TYPE.CIRCLE:
                        currentFrame.X+=animateSign;
                        if (currentFrame.X >= sheetSize.X)
                        {
                            currentFrame.X = 0;
                            ++currentFrame.Y;
                            if (currentFrame.Y >= sheetSize.Y)
                            {
                                currentFrame.Y = sheetSize.Y - 2 ;
                                currentFrame.X = sheetSize.X -1 ;
                                animateSign *= -1;
                            }
                        }
                        else if (currentFrame.X < 0)
                        {
                            currentFrame.X = sheetSize.X - 1;
                            --currentFrame.Y;
                            if (currentFrame.Y < 0)
                            {
                                currentFrame.Y = 1;
                                currentFrame.X = 0;
                                animateSign *= -1;
                            }
                        }
                        break;
                }
                
                
            }
        }

        public virtual void Draw(GameTime gameTime, SpriteBatch spriteBatch)
        {
            if (Visible && !drawEachScale)
            {
                spriteBatch.Draw(textureImage,
                    position,
                    new Rectangle(currentFrame.X * frameSize.X,
                        currentFrame.Y * frameSize.Y,
                        frameSize.X, frameSize.Y),
                    color, rotation, origin,
                    scale, spriteEffect, 0);
                if (this.collisionRectImage != null)
                {
                    spriteBatch.Draw(collisionRectImage, this.collisionRect, Color.White);
                }
            }
            else if(Visible && drawEachScale)
            {
                spriteBatch.Draw(textureImage, new Rectangle((int)position.X, (int)position.Y, 
                    (int)this.Width,(int)this.Height),
                     new Rectangle(currentFrame.X * frameSize.X,
                        currentFrame.Y * frameSize.Y,
                        frameSize.X, frameSize.Y), color, rotation, origin, spriteEffect, 0);
            }
        }

        public bool IsOutOfBounds(Rectangle clientRect)
        {
            if (position.X < -frameSize.X ||
                position.X > clientRect.Width ||
                position.Y < -frameSize.Y ||
                position.Y > clientRect.Height)
            {
                return true;
            }
            return false;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="bgPos">Position inside the textureImage</param>
        /// <param name="widthScale"></param>
        /// <param name="heightScale"></param>
        /// <returns>return CollisionRect if bgPos outside the textureImage</returns>
        public Rectangle CreateCollisionRect(Vector2 startPos, float width, float height)
        {
            if (startPos.X > position.X + this.Width || startPos.Y >position.Y + this.Height)
            {
                return this.collisionRect;
            }
            return new Rectangle(
                    (int)(position.X + startPos.X),
                    (int)(position.Y + startPos.Y),
                    (int)(width),
                    (int)(height));
        }

        public void setEdgeScale(float widthScale, float heightScale)
        {
            drawEachScale = true;
            this.scaleWidth = widthScale;
            this.scaleHeight = heightScale;
        }

    }
}
